package com.ld.shieldsb.common.core.util.date;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.DayOfWeek;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalField;
import java.time.temporal.WeekFields;
import java.util.Calendar;
import java.util.Date;

import lombok.extern.slf4j.Slf4j;

/**
 * java8的日期时间工具类
 * 
 * @author lv
 *
 */
@Slf4j
public final class DateTimeUtil {
    public static final DateTimeFormatter DATETIME_FORMATE = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
    public static final DateTimeFormatter DATE_FORMATE = DateTimeFormatter.ofPattern("uuuu-MM-dd");
    public static final DateTimeFormatter TIME_FORMATE = DateTimeFormatter.ofPattern("HH:mm:ss");

    private DateTimeUtil() {
        super();
    }

    /**
     * 获取uuuu-MM-dd HH:mm:ss格式的时间字符串
     * 
     * @Title getNowDateStr
     * @author 吕凯
     * @date 2016年7月28日 上午8:36:24
     * @return String
     */
    public static String getNowDateTimeStr() {
        return getNowDateTimeStrByFormatter(DATETIME_FORMATE);
    }

    /**
     * 获取uuuu-MM-dd格式的日期字符串
     * 
     * @Title getNowDateStr
     * @author 吕凯
     * @date 2016年7月28日 上午8:36:24
     * @return String
     */
    public static String getNowDateStr() {
        return getNowDateTimeStrByFormatter(DATE_FORMATE);
    }

    /**
     * 
     * 获取HH:mm:ss格式的时间字符串
     * 
     * @Title getNowTimeStr
     * @author 吕凯
     * @date 2016年7月28日 上午8:37:06
     * @return String
     */
    public static String getNowTimeStr() {
        return getNowDateTimeStrByFormatter(TIME_FORMATE);
    }

    /**
     * 
     * 根据传入的格式化对象返回字符串
     * 
     * @Title getNowDateTimeStrByFormatter
     * @author 吕凯
     * @date 2016年7月28日 上午8:37:28
     * @param formatter
     * @return String
     */
    public static String getNowDateTimeStrByFormatter(DateTimeFormatter formatter) {
        LocalDateTime datetime = LocalDateTime.now();
        return datetime.format(formatter);
    }

    /**
     * 将传入的毫秒数转化为uuuu-MM-dd HH:mm:ss格式的时间字符串
     * 
     * @Title getDateTimeString
     * @author 吕凯
     * @date 2016年7月28日 上午8:37:53
     * @param epochMilli
     * @return String
     */
    public static String getDateTimeString(long epochMilli) {
        Instant instants = Instant.ofEpochMilli(epochMilli);
        LocalDateTime datetime = LocalDateTime.ofInstant(instants, ZoneId.systemDefault());
        return datetime.format(DATETIME_FORMATE);
    }

    /**
     * 
     * uuuu-MM-dd格式的字符串转换为LocalDate
     * 
     * @Title str2date
     * @author 吕凯
     * @date 2016年7月28日 上午8:38:45
     * @param dateStr
     * @return LocalDate
     */
    public static LocalDate str2date(String dateStr) {
        if (dateStr == null) {
            return null;
        }
        try {
            return LocalDate.parse(dateStr, DATE_FORMATE);
        } catch (Exception e) {
            log.warn("日期转换错误，dateStr‘" + dateStr + "’，" + e.getMessage());
            return null;
        }
    }

    /**
     * 
     * 获取传入的uuuu-MM-dd格式的字符串转换为所在月份的第一天uuuu-MM-dd HH:mm:ss格式的时间字符串
     * 
     * @Title getMonthFirstTimeStr
     * @author 吕凯
     * @date 2016年7月28日 上午8:39:36
     * @param dateStr
     * @return String
     */
    public static String getMonthFirstTimeStr(String dateStr) {
        if (dateStr == null) {
            return null;
        }
        DateTimeFormatter f = DateTimeFormatter.ofPattern("uuuu-MM-dd");
        LocalDate date = LocalDate.parse(dateStr, f);
        return getMonthFirstTimeStr(date);
    }

    public static String getMonthFirstTimeStr(LocalDate date) {
        if (date == null) {
            return null;
        }
        DateTimeFormatter f1 = DateTimeFormatter.ofPattern("uuuu-MM-01");
        return date.format(f1) + " 00:00:00";
    }

    // 2021-06-23 00:00:00
    public static String getDateStartTimeStr(LocalDate date) {
        if (date == null) {
            return null;
        }
        return LocalDateTime.of(date, LocalTime.MIN).format(DATETIME_FORMATE);
    }

    // 2021-06-23 00:00:00
    public static String getNowStartTimeStr() {
        return getDateStartTimeStr(LocalDate.now());
    }

    // 2021-06-23 23:59:59
    public static String getDateEndTimeStr(LocalDate date) {
        if (date == null) {
            return null;
        }
        return LocalDateTime.of(date, LocalTime.MAX).format(DATETIME_FORMATE);
    }

    // 2021-06-23 23:59:59
    public static String getDateEndTimeStr() {
        return getDateEndTimeStr(LocalDate.now());
    }

    /**
     * 获取传入日期所在0时0分0秒时间
     * 
     * @Title getMonthFirstTime
     * @author 吕凯
     * @date 2016年8月8日 下午2:24:43
     * @param date
     * @return Date
     */
    public static Date getDate(Date date) {
        if (date == null) {
            return null;
        }
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    /**
     * 获取传入日期所在月份的第一天
     * 
     * @Title getMonthFirstTime
     * @author 吕凯
     * @date 2016年8月8日 下午2:24:43
     * @param date
     * @return Date
     */
    public static Date getMonthFirstTime(Date date) {
        if (date == null) {
            return null;
        }
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.DAY_OF_MONTH, 1);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    public static String getMonthLastTimeStr(String dateStr) {
        if (dateStr == null) {
            return null;
        }
        DateTimeFormatter f = DateTimeFormatter.ofPattern("uuuu-MM-dd");
        LocalDate date = LocalDate.parse(dateStr, f);
        return getMonthLastTimeStr(date);
    }

    public static String getMonthLastTimeStr(LocalDate date) {
        if (date == null) {
            return null;
        }
        YearMonth creditCardExpiry = YearMonth.of(date.getYear(), date.getMonth());
        DateTimeFormatter f1 = DateTimeFormatter.ofPattern("uuuu-MM-" + creditCardExpiry.lengthOfMonth());
        return date.format(f1) + " 23:59:59";
    }

    /**
     * 
     * 将传入的LocalDateTime对象转换为毫秒数
     * 
     * @Title dateTime2Milli
     * @author 吕凯
     * @date 2016年7月28日 上午8:45:34
     * @param datetime
     * @return long
     */
    public static long dateTime2Milli(LocalDateTime datetime) {
        if (datetime == null) {
            return 0;
        }
        return datetime.toInstant(ZoneOffset.of("+08:00")).toEpochMilli();
    }

    /**
     * 将传入的LocalDate对象转换为毫秒数
     * 
     * @Title dateTime2Milli
     * @author 吕凯
     * @date 2016年7月28日 上午8:45:12
     * @param date
     * @return long
     */
    public static long dateTime2Milli(LocalDate date) {
        if (date == null) {
            return 0;
        }
        return dateTime2Milli(date.atStartOfDay());
    }

    /**
     * 将传入的uuuu-MM-dd HH:mm:ss格式字符串转换为Date
     * 
     * @Title getStr2Date
     * @author 吕凯
     * @date 2016年7月28日 上午8:42:06
     * @param format
     * @return Date
     */
    public static Date str2SqlDate(String dateStr) {
        if (dateStr == null) {
            return null;
        }
        LocalDate date = LocalDate.parse(dateStr, DATETIME_FORMATE);
        return new Date(dateTime2Milli(date));
    }

    /**
     * localDate转date
     * 
     * @Title localDate2Date
     * @author 吕凯
     * @date 2021年6月18日 下午2:58:58
     * @param localDate
     * @return Date
     */
    public static Date localDate2Date(LocalDate localDate) {
        if (null == localDate) {
            return null;
        }
        ZonedDateTime zonedDateTime = localDate.atStartOfDay(ZoneId.systemDefault());
        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * date转localDate
     * 
     * @Title date2localDate
     * @author 吕凯
     * @date 2021年6月18日 下午2:59:11
     * @param date
     * @return LocalDate
     */
    public static LocalDate date2localDate(Date date) {
        if (null == date) {
            return null;
        }
        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    }

    /**
     * localDateTime转Date
     * 
     * @Title localDateTime2Date
     * @author 吕凯
     * @date 2021年6月18日 下午2:59:23
     * @param localDateTime
     * @return Date
     */
    public static Date localDateTime2Date(LocalDateTime localDateTime) {
        if (null == localDateTime) {
            return null;
        }
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 
     * date转localDateTime
     * 
     * @Title date2localDateTime
     * @author 吕凯
     * @date 2021年6月18日 下午2:59:35
     * @param date
     * @return LocalDateTime
     */
    public static LocalDateTime date2localDateTime(Date date) {
        if (null == date) {
            return null;
        }
        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
    }

    /**
     * 
     * 根据传入的格式化字符串格式化传入的日期
     * 
     * @Title getDateStr
     * @author 吕凯
     * @date 2016年7月28日 上午8:42:41
     * @param date
     * @param format
     * @return String
     */
    public static String getDateStr(Date date, String format) {
        if (date == null) {
            return null;
        }
        return new SimpleDateFormat(format).format(date);
    }

    /**
     * 将传入的yyyy-MM-dd格式字符串转换为Date
     * 
     * @Title getStr2Date
     * @author 吕凯
     * @date 2016年7月28日 上午8:42:06
     * @param format
     * @return Date
     */
    public static Date getStr2Date(String format) {
        Date date = null;
        try {
            date = new SimpleDateFormat("yyyy-MM-dd").parse(format);
        } catch (ParseException e) {
            log.error("", e);
        }
        return date;
    }

    /**
     * 
     * 得到两个日期相差的天数（只计算日期差不考虑小时数秒数等）
     * 
     * @Title daysBetween
     * @param early
     *            前一个天数
     * @param late
     *            后一个天数
     * @return int
     */
    public static final int daysBetween(Date early, Date late) {
        Calendar calst = Calendar.getInstance();
        Calendar caled = Calendar.getInstance();
        diffDates(calst, caled, early, late);
        // 得到两个日期相差的天数
        int days = ((int) (caled.getTime().getTime() / 1000) - (int) (calst.getTime().getTime() / 1000)) / 3600 / 24;
        return days;
    }

    /**
     * 设置精确到日期，忽略小时后面的精度
     * 
     * @Title diffDates
     * @author 吕凯
     * @date 2021年6月1日 上午9:34:01
     * @param calStart
     * @param calEnd
     * @param early
     * @param late
     *            void
     */
    private static void diffDates(Calendar calStart, Calendar calEnd, Date early, Date late) {
        calStart.setTime(early);
        calEnd.setTime(late);
        // 设置时间为0时
        calStart.set(Calendar.HOUR_OF_DAY, 0);
        calStart.set(Calendar.MINUTE, 0);
        calStart.set(Calendar.SECOND, 0);
        calEnd.set(Calendar.HOUR_OF_DAY, 0);
        calEnd.set(Calendar.MINUTE, 0);
        calEnd.set(Calendar.SECOND, 0);
    }

    /**
     * 
     * 得到两个日期相差的小时数
     * 
     * @Title hoursBetween
     * @param early
     * @param late
     * @return int
     */
    public static final int hoursBetween(Date early, Date late) {
        return minutesBetween(early, late) / 60;
    }

    /**
     * 
     * 得到两个日期相差的分钟数
     * 
     * @Title minutesBetween
     * @param early
     * @param late
     * @return int
     */
    public static final int minutesBetween(Date early, Date late) {
        return ((int) (late.getTime() / 1000) - (int) (early.getTime() / 1000)) / 60;
    }

    /**
     * 
     * 得到两个日期相差的毫秒数
     * 
     * @Title timeBetween
     * @param early
     * @param late
     * @return long
     */
    public static final long timeBetween(Date early, Date late) {
        return late.getTime() - early.getTime();
    }

    /**
     * 距今时间
     * 
     * @Title fromNow
     * @author 吕凯
     * @date 2021年6月1日 上午9:39:05
     * @param early
     * @return String
     */
    public static final String fromNow(Date early, boolean showDateTime, String format, String separator) {

        String fromNowStr = "";
        if (early == null) {
            return fromNowStr;
        }
        long now = System.currentTimeMillis();
        long deltime = (now - early.getTime()) / 1000; // 取秒数
        String postfix = "";
        if (deltime > 0) { // 大于0说明是之前的时间
            postfix = "前";
        } else if (deltime < 0) { // 小于0说明是之后的时间
            postfix = "后";
        }
        deltime = Math.abs(deltime); // 取绝对值
        if (deltime > 365 * 24 * 60 * 60) {
            fromNowStr = (int) (deltime / (365 * 24 * 60 * 60)) + "年";
        } else if (deltime > 7 * 24 * 60 * 60) {
            fromNowStr = (int) (deltime / (7 * 24 * 60 * 60)) + "周";
        } else if (deltime > 24 * 60 * 60) {
            fromNowStr = (int) (deltime / (24 * 60 * 60)) + "天";
        } else if (deltime > 60 * 60) {
            fromNowStr = (int) (deltime / (60 * 60)) + "小时";
        } else if (deltime > 60) {
            fromNowStr = (int) (deltime / (60)) + "分钟";
        } else if (deltime > 10) {
            fromNowStr = deltime + "秒";
        } else {
            fromNowStr = "刚刚";
        }
        fromNowStr += postfix; // 加上后缀
        if (showDateTime) {
            fromNowStr = getDateStr(early, format) + separator + "(" + fromNowStr + ")";
        }

        return fromNowStr;
    }

    /**
     * 距现在时间，分隔符为空格
     * 
     * @Title fromNow
     * @author 吕凯
     * @date 2021年6月1日 上午9:53:44
     * @param early
     * @param showDateTime
     * @param format
     * @return String
     */
    public static final String fromNow(Date early, boolean showDateTime, String format) {
        return fromNow(early, showDateTime, format, " ");
    }

    /**
     * 距现在时间，格式化字符串默认yyyy-MM-dd HH:mm:ss，分隔符为空格
     * 
     * @Title fromNow
     * @author 吕凯
     * @date 2021年6月1日 上午9:54:00
     * @param early
     * @param showDateTime
     * @return String
     */
    public static final String fromNow(Date early, boolean showDateTime) {
        return fromNow(early, showDateTime, "yyyy-MM-dd HH:mm:ss");
    }

    /**
     * 获取距现在时间的字符串，带原日期
     * 
     * @Title fromNow
     * @author 吕凯
     * @date 2021年6月1日 上午9:50:46
     * @param early
     * @return String
     */
    public static final String fromNow(Date early) {
        return fromNow(early, true);
    }

    /**
     * 只获取距现在时间的字符串，不带原日期
     * 
     * @Title fromNowShort
     * @author 吕凯
     * @date 2021年6月1日 上午9:51:38
     * @param early
     * @return String
     */
    public static final String fromNowShort(Date early) {
        return fromNow(early, false, null, null);
    }

    public static String dateTime2Str(LocalDateTime date) {
        return date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }

    /**
     * 转换为日
     * 
     * @Title date2Str
     * @author 吕凯
     * @date 2021年7月23日 上午8:41:36
     * @param date
     * @return String
     */
    public static String date2Str(LocalDateTime date) {
        return date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
    }

    /**
     * 自定义转换格式
     * 
     * @Title dateTime2Str
     * @author 吕凯
     * @date 2021年7月23日 上午8:41:46
     * @param date
     * @param pattern
     * @return String
     */
    public static String dateTime2Str(LocalDateTime date, String pattern) {
        return date.format(DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 转换为日
     * 
     * @Title date2Str
     * @author 吕凯
     * @date 2021年7月23日 上午8:41:36
     * @param date
     * @return String
     */
    public static String date2Str(LocalDate date) {
        return date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
    }

    /**
     * 自定义转换格式
     * 
     * @Title dateTime2Str
     * @author 吕凯
     * @date 2021年7月23日 上午8:41:46
     * @param date
     * @param pattern
     * @return String
     */
    public static String date2Str(LocalDate date, String pattern) {
        return date.format(DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 获取周的第一天（即周一日期）
     * 
     * @Title getStartDayOfWeek
     * @author 吕凯
     * @date 2021年7月13日 下午5:23:28
     * @param date
     * @return LocalDateTime
     */
    public static LocalDateTime getStartDayOfWeek(LocalDate date) {
        if (date == null) {
            date = LocalDate.now(ZoneId.systemDefault());
        }
        WeekFields weeks = WeekFields.of(DayOfWeek.MONDAY, 1); // 周一为第一天，默认周日
        DayOfWeek firstDayOfWeek = weeks.getFirstDayOfWeek();
        return date.with(firstDayOfWeek).atStartOfDay();
    }

    /**
     * 获取x年第x周的周一
     * 
     * @Title getStartDayOfWeek
     * @author 吕凯
     * @date 2021年7月23日 上午9:05:39
     * @param year
     *            年份
     * @param weeknum
     *            本年第几周
     * @return LocalDate
     */
    public static LocalDate getStartDayOfWeek(int year, int weeknum) {

        return LocalDate.parse(year + "-W" + (weeknum < 10 ? ("0" + weeknum) : weeknum) + "-1", DateTimeFormatter.ISO_WEEK_DATE);
    }

    /**
     * 获取周的最后一天（即周日日期）
     * 
     * @Title getEndDayOfWeek
     * @author 吕凯
     * @date 2021年7月13日 下午5:23:40
     * @param date
     * @return LocalDateTime
     */
    public static LocalDateTime getEndDayOfWeek(LocalDate date) {
        if (date == null) {
            date = LocalDate.now(ZoneId.systemDefault());
        }
        TemporalField fieldIso = WeekFields.of(DayOfWeek.MONDAY, 1).dayOfWeek();
        LocalDate localDate = LocalDate.from(date);
        localDate = localDate.with(fieldIso, 7);
        return localDate.atStartOfDay();
    }

    /**
     * 获取x年第x周的周日，
     * 
     * @Title getStartDayOfWeek
     * @author 吕凯
     * @date 2021年7月23日 上午9:05:39
     * @param year
     *            年份
     * @param weeknum
     *            本年第几周
     * @return LocalDate
     */
    public static LocalDate getEndDayOfWeek(int year, int weeknum) {

        return LocalDate.parse(year + "-W" + (weeknum < 10 ? ("0" + weeknum) : weeknum) + "-7", DateTimeFormatter.ISO_WEEK_DATE);
    }

    /*可以看到一年的第一个自然周应当满足：
    
    1,有第一个星期四
    2,包含1月4号
    3,第一个自然周应当有4个或者4个以上的天数
    4,这个星期开始的时间（即周一）在去年的12月29号（星期一）到今年的1月4号之间
    所以如果1月1号是周一、周二、周三或者周四，它属于第一个自然周，如果不是，他属于去年的52周或者53周。*/
    /**
     * 获取给定的日期在一年中的周数，需要注意的是，ISO8601的标准中，至少需要4天才能算作1周，如果某年的第一天是周五、周六或周日(比如2021年)，那么这一年的第一周是从下一周开始的
     * 
     * @Title getWeekOfYear
     * @author 吕凯
     * @date 2021年7月14日 上午9:44:27
     * @param date
     * @return int
     */
    public static int getWeekOfYear(LocalDate date) {
        WeekFields weekFields = WeekFields.ISO; // 周一为第一天，默认周日
        return date.get(weekFields.weekOfWeekBasedYear());
    }

    /**
     * 获取给定年份的最大周数
     * 
     * @Title getMaxWeekNumOfYear
     * @author 吕凯
     * @date 2021年7月23日 上午8:50:35
     * @param year
     * @return int
     */
    public static int getMaxWeekNumOfYear(int year) {
        LocalDate time = LocalDate.of(year, 12, 31);
        return getWeekOfYear(time);
    }

    public static int getMaxWeekNumOfYear(LocalDate date) {
        LocalDate time = LocalDate.of(date.getYear(), 12, 31);
        return getWeekOfYear(time);
    }

    /**
     * 获取今年的最大周数
     * 
     * @Title getMaxWeekNumOfThisYear
     * @author 吕凯
     * @date 2021年7月23日 上午8:52:40
     * @return int
     */
    public static int getMaxWeekNumOfThisYear() {
        return getMaxWeekNumOfYear(LocalDate.now());
    }

    /**
     * 获取年份与周数的字符串
     * 
     * @Title getYearWeeklyStr
     * @author 吕凯
     * @date 2021年7月26日 下午2:44:59
     * @param year
     * @param index
     * @return String
     */
    public static String getYearWeeklyStr(int year, int weekly) {
        return year + "" + (weekly < 10 ? ("0" + weekly) : weekly);
    }

}
